﻿module FTPServerSetting

open System
open System.Xml
open System.Xml.Linq
open System.IO
open System.Diagnostics
open Extensions
open Common
open System.Threading

module private Util =
 
    ///使用string的replace修改userName 和userPwdHex即可
    let  userXmlTemplate =
        "<User Name=\"userName\">
              <Option Name=\"Pass\">userPwdHex</Option>
              <Option Name=\"Group\">YLs</Option>
              <Option Name=\"Bypass server userlimit\">2</Option>
              <Option Name=\"User Limit\">0</Option>
              <Option Name=\"IP Limit\">0</Option>
              <Option Name=\"Enabled\">2</Option>
              <Option Name=\"Comments\"></Option>
              <Option Name=\"ForceSsl\">2</Option>
              <IpFilter>
                <Disallowed />
                <Allowed />
              </IpFilter>
              <Permissions>
                <Permission Dir=\"F:\FTPServer\userName\">
                  <Option Name=\"FileRead\">1</Option>
                  <Option Name=\"FileWrite\">1</Option>
                  <Option Name=\"FileDelete\">0</Option>
                  <Option Name=\"FileAppend\">0</Option>
                  <Option Name=\"DirCreate\">0</Option>
                  <Option Name=\"DirDelete\">0</Option>
                  <Option Name=\"DirList\">1</Option>
                  <Option Name=\"DirSubdirs\">1</Option>
                  <Option Name=\"IsHome\">1</Option>
                  <Option Name=\"AutoCreate\">0</Option>
                </Permission>
              </Permissions>
              <SpeedLimits DlType=\"0\" DlLimit=\"10\" ServerDlLimitBypass=\"2\" UlType=\"0\" UlLimit=\"10\" ServerUlLimitBypass=\"2\">
                <Download />
                <Upload />
              </SpeedLimits>
            </User>
        "
    let  BuildUser name pwd =
        let pwdHex =pwd |> HashAlgorithm.getHex_MD5
        userXmlTemplate.Replace("userName",name).Replace("userPwdHex",pwdHex)
        |> XElement.Parse


    /// path -> name -> dir
    let  createDir  (path:string) (name :string)=
        let dir =conbindPath path name 
        dir |>Directory.CreateDirectory |>ignore
        dir
    ///delete all files on  dir   before delete dir 
    /// path -> name -> unit
    let DeleteDir path name =
        let dir =conbindPath path name
        let files = Directory.GetFiles(dir)
        files|>Array.iter (fun fname -> File.Delete fname)
        dir|> Directory.Delete
        

open Util

type SettingManager(cp:string) = 
    ///缓存设置对象
    static let mutable  smOption:SettingManager option =None
    let fs =File.OpenRead(cp)
    let doc' =XDocument.Load(fs)
    let mutable  configPath =cp
    let   doc :XDocument= doc'
    do
        fs.Dispose()
    static member GetSettingManager(configPath:string)=
        match smOption with
        | None ->
            let sm =new SettingManager(configPath) 
            smOption <- Some(sm)
            sm
        | Some(v) -> v
    member private m.saveAndReloadConfig()=
        m.saveConfig  ()
        m.reloadConfig()
    member private m.saveConfig ()=
            use fs = File.OpenWrite(configPath)
            use sw = new StreamWriter(fs)
            sw.Write(doc.ToString())
    member m.reloadConfig ()=
        let dir =getDir configPath
        let exePath= dir + "\\FileZilla server.exe"
        Process.Start(exePath,"/reload-config").WaitForExit()

    member m.DeleteUser name =
        let user = doc.findUser name
        user.Remove()
        m.saveAndReloadConfig()

    member m.AddUser name pwd =
        let user = BuildUser name pwd 
        doc.addUser user
        m.saveAndReloadConfig()
    member m.ResetUserPassword name newPwd =
        let u =doc.findUser name
        u.updateUserPassword (newPwd|>HashAlgorithm.getHex_MD5)
        m.saveAndReloadConfig()
    member m.ResetUserPasswordInCache name newPwd =
        let u =doc.findUser name
        u.updateUserPassword (newPwd|>HashAlgorithm.getHex_MD5)
        m.saveAndReloadConfig()
    /// 随机化用户的ftp密码.影响新能，需要锁住文件。
    member m.RandomPassword name pwdLen=
        let pwd =HashAlgorithm.randomWord pwdLen 
        m.ResetUserPassword name pwd
        pwd
    /// 读取用户的ftp密码
//    member m.GetPassword name =
//        doc.findUser(name)
//        
//        ""
    member m.GetHomeDir() =
            doc.Element("FileZillaServer")
                .Element("Groups")
                .Element("Group",fun g->g.Attribute("Name").Value="YLs")
                .Element("Permissions").Element("Permission").Attribute("Dir").Value 
    /// name -> dir
    member m.CreateUserOnDisk name =
            let dir =m.GetHomeDir()
            createDir dir name
    member m.GetUserHomeDir name =
        let user = doc.findUser name
        user.Element("Permissions").Element("Permission").Attribute("Dir").Value
    /// 工作项文件夹名字是 boyName&grilName\模板名
    ///返回相对路径
    member m.AddWorkItemDir userName workItemName tempLateName=
        let dir = m.GetUserHomeDir userName
        let dir' =createDir dir workItemName
        createDir dir' tempLateName |>ignore 
        "\\"+workItemName+"\\"+tempLateName
    /// 工作项文件夹名字就是boyName 与grilName 的拼接
    member m.DeleteWorkItemDir userName workItemName=
        let dir = m.GetUserHomeDir userName
        DeleteDir dir workItemName
    member m.AddTemplateDir serverUsername  templateDir templateName=
        let dir = m.GetUserHomeDir serverUsername
        let dir' =createDir dir (conbindPath templateDir templateName)
        "\\"+templateDir+"\\"+templateName
    member m.DeleteTemplateDir serverUsername templateDir templateName=
        let dir = m.GetUserHomeDir serverUsername
        DeleteDir dir (conbindPath templateDir templateName)
//   #r "System.Xml.Linq";;        
//   #load "HashAlgorithm.fs";;
//   #load "Common.fs"
//   #load "Extensions.fs"
//   #load "FTPServerSetting.fs";;
//    open FTPServerSetting;;
//   let sm =new SettingManager(@"E:\Program Files (x86)\FileZilla Server\FileZilla Server.xml");;
//   sm.AddUser "test" "test";;
//   sm.ResetUserPassword "test" "jzjz";;
//   sm.RandomPassword "test" 8

//cool Success
